package fcnet

import (
	"bytes"
	"encoding/binary"
	"errors"

	"gitee.com/fcsvr/fc/fclog"
)

const (
	HEAD_LEN uint8 = 16

	CODEC_JSON  uint8 = 1
	CODEC_MSGPK uint8 = 2
)

type Head struct {
	ID        uint32
	Magic     uint16
	Typ       uint8
	Version   uint8
	CodecTyp  uint8
	HeadLen   uint8
	HeadExLen uint16
	BodyLen   uint32
}

type Msg struct {
	Head
	HeadEx []byte
	Body   []byte
}

func NewMsgNull() *Msg {
	msg := &Msg{
		Head: Head{
			HeadLen: uint8(HEAD_LEN),
		},
	}
	return msg
}

func NewMsg(id uint32, body []byte) *Msg {
	msg := &Msg{
		Head: Head{
			ID:       id,
			HeadLen:  uint8(HEAD_LEN),
			BodyLen:  uint32(len(body)),
			Typ:      uint8(1),
			Version:  uint8(10),
			CodecTyp: CODEC_MSGPK,
		},

		Body: body,
	}
	return msg
}

func (this Head) GetMsgMagic() uint16 {
	return this.Magic
}
func (this Head) GetMsgID() uint32 {
	return this.ID
}
func (this *Head) SetMsgID(id uint32) {
	this.ID = id
}
func (this Head) GetMsgTyp() uint8 {
	return this.Typ
}
func (this Head) GetMsgVersion() uint8 {
	return this.Version
}
func (this Head) GetMsgCodecTyp() uint8 {
	return this.CodecTyp
}
func (this Head) GetMsgHeadLen() uint8 {
	return this.HeadLen
}
func (this Head) GetMsgHeadExLen() uint16 {
	return this.HeadExLen
}
func (this Head) GetMsgBodyLen() uint32 {
	return this.BodyLen
}
func (this *Head) SetBodyLen(l uint32) {
	this.BodyLen = l
}

func (this *Msg) GetMsgHead() any {
	return this.Head
}
func (this *Msg) GetMsgHeadEx() any {
	return this.HeadEx
}
func (this *Msg) GetMsgBody() []byte {
	return this.Body
}
func (this *Msg) SetMsgBody(body []byte) {
	this.Body = body
}

func (this *Msg) DoPack() ([]byte, error) {
	buff := bytes.NewBuffer([]byte{})
	if err := binary.Write(buff, binary.LittleEndian, this.GetMsgHead()); err != nil {
		return nil, err
	}
	if err := binary.Write(buff, binary.LittleEndian, this.GetMsgHeadEx()); err != nil {
		return nil, err
	}
	if err := binary.Write(buff, binary.LittleEndian, this.GetMsgBody()); err != nil {
		return nil, err
	}
	return buff.Bytes(), nil
}

func (this *Msg) UnPack(data []byte) error {
	buff := bytes.NewReader(data)
	if err := binary.Read(buff, binary.LittleEndian, &this.Head); err != nil {
		return err
	}
	fclog.Debug("Msg UnPack data = %+v", this.Head)
	if this.BodyLen > uint32(SvrMgr.ConfigSvr().MaxPackLen) {
		return errors.New("Svr recv pack data too long")
	}

	return nil
}
